package com.dycong.common.IO.netty.first;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.net.InetSocketAddress;
import java.util.logging.Logger;

/**
 * Created by dycong on 2017/3/13.
 */
public class EchoServer {

    Logger logger = Logger.getLogger(EchoServer.class.getName());
    private   int PORT;

    public EchoServer(int port) {
        this.PORT = port;
    }

    public static void main(String[] args) {
        if (args.length != 0)
            new EchoServer(Integer.valueOf(args[0])).start();
        else
            new EchoServer(9090).start();
    }

    private void start() {
        NioEventLoopGroup group1 = new NioEventLoopGroup();
        NioEventLoopGroup group2 = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap
                    .group(group1,group2)       //我们已指定 NioEventLoopGroup接受和处理新连接
                    .channel(NioServerSocketChannel.class)      //指定 NioServerSocketChannel为信道类型
                    .localAddress(new InetSocketAddress(PORT))
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new EchoServerHandler());     //TODO 在这里我们使用一个特殊的类，ChannelInitializer 。当一个新的连接被接受，一个新的子 Channel 将被创建， ChannelInitializer 会添加我们新的EchoServerHandler 的实例到 Channel 的 ChannelPipeline。正如我们如前所述，如果有入站信息，这个处理器将被通知。+
                        }
                    });
            //最后绑定服务器等待直到绑定完成，调用sync()方法会阻塞直到服务器完成绑定,然后服务器等待通道关闭，因为使用sync()，所以关闭操作也会被阻塞。
            // Start the server.
            ChannelFuture channelFuture = serverBootstrap.bind().sync();          //sync() 等待，直到异步操作执行完毕，核心思想同await。我们得到Future实例后，可以使用sync()方法来阻塞当前线程，直到异步操作执行完毕。
            System.out.println(Thread.currentThread().getName());
            // Wait until the server socket is closed.阻塞等待server socket关闭
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {

        } finally {
            try {
                group1.shutdownGracefully().sync();          //关闭下 EventLoopGroup 并释放所有资源，包括所有创建的线程
                group2.shutdownGracefully().sync();          //关闭下 EventLoopGroup 并释放所有资源，包括所有创建的线程
            } catch (InterruptedException e) {

            }
        }
    }

}
